home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
boot
/
netBoot.new
/
dev
/
if_le.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-19
|
12KB
|
464 lines
#ifdef M25
#ifndef lint
static char sccsid[] = "@(#)if_le.c 1.1 86/09/27 Copyr 1986 Sun Micro";
#endif
/*
* Copyright (c) 1986 by Sun Microsystems, Inc.
*/
/*****************************************************************************
* 10-Dec-85
* ADD signal user that we have lost carrier (or couldn't find it).
* This usually means that the cable is bad
*
*****************************************************************************/
/*
* For Sun-3/25 debugging we want DEBUG on. For production, turn it off.
*/
/* #define DEBUG1 */
/* #define DEBUG 1 */
#define LANCEBUG 1 /* Rev C Lance chip bug */
#define PROTOSCRATCH 8192
/*
* Parameters controlling TIMEBOMB action: times out if chip hangs.
*
*/
#define TIMEBOMB 1000000 /* One million times around is all... */
/*
* Sun Lance Ethernet Controller interface
*/
#include "../dev/saio.h"
#include "../h/param.h"
#include "../h/socket.h"
#include "../dev/if_lereg.h"
#include "../dev/if.h"
#include "../h/in.h"
#include "../dev/if_ether.h"
#include "../h/idprom.h"
#include "../sun3/cpu.map.h"
/* Determine whether we are PROM or not. */
/* #define PROM 1 */
int lancexmit(), lancepoll(), lancereset();
struct saif leif = {
lancexmit,
lancepoll,
lancereset,
};
#define LANCERBUFSIZ 1600
#define LANCETBUFSIZ 1600
struct lance_softc {
/* char es_scrat[PROTOSCRATCH]; /* work space for nd */
struct le_device *es_lance; /* Device register address */
struct ether_addr es_enaddr; /* Our Ethernet address */
struct le_init_block es_ib; /* Initialization block */
u_char fill[6];
struct le_md es_rmd[2]; /* Receive Descriptor Ring */
struct le_md es_tmd; /* Transmit Descriptor Ring */
u_char es_rbuf[2][LANCERBUFSIZ]; /* Receive Buffers */
#ifndef PROM
u_char es_tbuf[LANCETBUFSIZ]; /* Transmit Buffer */
#endif PROM
int es_next_rmd; /* Next descriptor in ring */
};
/*
* Need to initialize the Ethernet control reg to:
* Reset is active
* Loopback is NOT active
* Interrupt enable is not active.
*/
u_long lancestd[] = {VIOPG_AMD_ETHER << BYTES_PG_SHIFT};
struct devinfo lanceinfo = {
sizeof (struct le_device),
sizeof (struct lance_softc),
0, /* Local bytes (we use dma) */
1, /* Standard addr count */
lancestd, /* Standard addrs */
MAP_OBIO, /* Device type */
0, /* transfer size handled by ND */
};
int lanceprobe(), tftpboot(), lanceopen(), lanceclose(), etherstrategy();
int nullsys();
struct boottab ledriver = {
"le", lanceprobe, tftpboot, lanceopen, lanceclose,
etherstrategy, "le: Sun/Lance Ethernet", &lanceinfo,
};
extern struct ether_addr etherbroadcastaddr;
/*
* Probe for device.
* Must return -1 for failure for monitor probe
*/
lanceprobe(sip)
struct saioreq *sip;
{
register short *sp;
struct idprom id;
if (IDFORM_1 == idprom(IDFORM_1, &id)
&& id.id_machine == IDM_SUN3_M25)
return (0);
else
return (-1);
}
/*
* Open Lance Ethernet nd connection, return -1 for errors.
*/
lanceopen(sip)
struct saioreq *sip;
{
register int result;
#ifdef DEBUG1
printf("le: lanceopen[\n");
#endif DEBUG1
sip->si_sif = &leif;
if ( lanceinit(sip) || (result = etheropen(sip)) < 0 ) {
lanceclose(sip); /* Make sure we kill chip */
#ifdef DEBUG1
printf("le: lanceopen --> -1\n");
#endif DEBUG1
return (-1);
}
#ifdef DEBUG1
printf("le: lanceopen --> %x\n", result);
#endif DEBUG1
return (result);
}
/*
* Set up memory maps and Ethernet chip.
* Returns 1 for error (after printing message), 0 for ok.
*/
int
lanceinit(sip)
struct saioreq *sip;
{
register struct lance_softc *es;
int paddr;
int i;
struct idprom id;
/*
* Our locals were obtined from DMA space, now put the locals
* pointer in the standard place. This is OK since close()
* will only deallocate from devdata if its size in devinfo is >0.
*/
es = (struct lance_softc *)sip->si_dmaaddr;
sip->si_devdata = (caddr_t)es;
es->es_lance = (struct le_device *) sip->si_devaddr;
if (IDFORM_1 != idprom(IDFORM_1, &id)) {
printf("le: No ID PROM\n");
return 1;
}
return lancereset(es, sip);
}
/*
* Basic Lance initialization
* Returns 1 for error (after printing message), 0 for ok.
*/
int
lancereset(es, sip)
register struct lance_softc *es;
struct saioreq *sip;
{
register struct le_device *le = es->es_lance;
register struct le_init_block *ib = &es->es_ib;
int timeout = TIMEBOMB;
int i;
#ifdef DEBUG1
printf("le: lancereset(%x, %x)\n", es, sip);
#endif DEBUG1
/* Reset the chip */
le->le_rap = LE_CSR0;
le->le_csr = LE_STOP;
/* Perform the basic initialization */
/* Construct the initialization block */
bzero((caddr_t)&es->es_ib, sizeof (struct le_init_block));
/* Leave the mode word 0 for normal operating mode */
myetheraddr(&es->es_enaddr);
/* Oh, for a consistent byte ordering among processors */
ib->ib_padr[0] = es->es_enaddr.ether_addr_octet[1];
ib->ib_padr[1] = es->es_enaddr.ether_addr_octet[0];
ib->ib_padr[2] = es->es_enaddr.ether_addr_octet[3];
ib->ib_padr[3] = es->es_enaddr.ether_addr_octet[2];
ib->ib_padr[4] = es->es_enaddr.ether_addr_octet[5];
ib->ib_padr[5] = es->es_enaddr.ether_addr_octet[4];
/* Leave address filter 0 -- we don't want Multicast packets */
ib->ib_rdrp.drp_laddr = (long)&es->es_rmd[0];
ib->ib_rdrp.drp_haddr = (long)&es->es_rmd[0] >> 16;
ib->ib_rdrp.drp_len = 1; /* 2 to the 1 power = 2 */
ib->ib_tdrp.drp_laddr = (long)&es->es_tmd;
ib->ib_tdrp.drp_haddr = (long)&es->es_tmd >> 16;
ib->ib_tdrp.drp_len = 0; /* 2 to the 0 power = 1 */
/* Clear all the descriptors */
bzero((caddr_t)es->es_rmd, 2 * sizeof (struct le_md));
bzero((caddr_t)&es->es_tmd, sizeof (struct le_md));
/* Give the init block to the chip */
le->le_rap = LE_CSR1; /* select the low address register */
le->le_rdp = (long)ib & 0xffff;
le->le_rap = LE_CSR2; /* select the high address register */
le->le_rdp = ((long)ib >> 16) & 0xff;
le->le_rap = LE_CSR3; /* Bus Master control register */
le->le_rdp = LE_BSWP;
le->le_rap = LE_CSR0; /* main control/status register */
le->le_csr = LE_INIT;
while( ! (le->le_csr & LE_IDON) ) {
if (timeout-- <= 0) {
printf("le: cannot initialize\n");
return (1);
}
}
le->le_csr = LE_IDON; /* Clear the indication */
/* Hang out the receive buffers */
es->es_next_rmd = 0;
install_buf_in_rmd(es->es_rbuf[0], &es->es_rmd[0]);
install_buf_in_rmd(es->es_rbuf[1], &es->es_rmd[1]);
le->le_csr = LE_STRT;
#ifdef DEBUG1
printf("le: lancereset returns OK\n");
#endif DEBUG1
return 0; /* It all worked! */
}
install_buf_in_rmd(buffer, rmd)
u_char *buffer;
register struct le_md *rmd;
{
rmd->lmd_ladr = (u_short)buffer;
rmd->lmd_hadr = (long)buffer >> 16;
rmd->lmd_bcnt = -LANCERBUFSIZ;
rmd->lmd_mcnt = 0;
rmd->lmd_flags = LMD_OWN;
}
/*
* Transmit a packet.
* If possible, just points to the packet without copying it anywhere.
*/
lancexmit(es, buf, count)
register struct lance_softc *es;
char *buf;
int count;
{
register struct le_device *le = es->es_lance;
struct le_md *tmd = &es->es_tmd; /* Transmit Msg. Descriptor */
caddr_t tbuf;
int timeout = TIMEBOMB;
#ifdef DEBUG2
printf( "xmit np_blkno %x\n",
((struct ndpack *)(buf+14))->np_blkno);
#endif DEBUG2
/*
* We assume the buffer is in an area accessible by the chip.
* The caller of xmit is currently ndxmit(), which only sends
* an nd structure, which we happen to know is allocated in the
* right area (in fact, it's part of the struct nd which
* is the first thing in our own es structure). If we wish to
* use xmit for some other purpose, the buffer might not be
* accessible by the chip, so to be general we ought to copy
* into some accessible place. HOWEVER, PROM space is really tight,
* so this generality is not free.
*/
#ifdef PROM
tbuf = buf;
if (((int)tbuf & 0x00F00000) == 0)
(int)tbuf |= 0x00F00000;
#else PROM
/* FIXME, constant address masks here! */
if ( ((int)buf & 0x0F000000) == 0x0F000000) { /* we can point to it */
tbuf = buf;
} else {
tbuf = (caddr_t)es->es_tbuf;
bcopy((caddr_t)buf, tbuf, count);
}
#endif PROM
tmd->lmd_hadr = (int)tbuf >> 16;
tmd->lmd_ladr = (u_short) tbuf;
tmd->lmd_bcnt = -count;
#ifdef notdef
if (tmd->lmd_bcnt < -MINPACKET)
tmd->lmd_bcnt = -MINPACKET;
#endif notdef
tmd->lmd_flags3 = 0;
tmd->lmd_flags = LMD_STP | LMD_ENP | LMD_OWN;
le->le_csr = LE_TDMD;
do {
if ( le->le_csr & LE_TINT ) {
le->le_csr = LE_TINT; /* Clear interrupt */
break;
}
} while ( --timeout > 0);
/*****************************************************************************
* 10-Dec-85
* ADD signal user that we have lost carrier (or couldn't find it).
* This usually means that the cable is bad
*
*****************************************************************************/
if (tmd->lmd_flags & LMD_ERR)
{
if (tmd->lmd_flags3 & TMD_LCAR) /* (AMD Lance Transmit msg */
/* descriptor - 3 (TMD3) */
printf("le: No Carrier\n");
}
/*****************************************************************************/
if ( (tmd->lmd_flags & LMD_ERR)
|| (tmd->lmd_flags3 & TMD_BUFF)
|| (timeout <= 0) ) {
#ifdef DEBUG
printf("le: xmit failed - tmd1 flags %x tmd3 %x csr0 %x\n",
tmd->lmd_flags, tmd->lmd_flags3, le->le_csr);
#endif DEBUG
return (1);
}
return (0);
}
int
lancepoll(es, buf)
register struct lance_softc *es;
char *buf;
{
register struct le_device *le = es->es_lance;
register struct le_md *rmd;
register struct ether_header *header;
int length;
#ifdef DEBUG1
printf("le: poll\n");
#endif DEBUG1
if ( ! (le->le_csr & LE_RINT) )
return (0); /* No packet yet */
#ifdef DEBUG1
printf("le: received packet\n");
#endif DEBUG1
le->le_csr = LE_RINT; /* Clear interrupt */
rmd = &es->es_rmd[es->es_next_rmd];
if ( (rmd->lmd_flags & ~RMD_OFLO) != (LMD_STP|LMD_ENP) ) {
#ifdef DEBUG
printf("Receive packet error - rmd flags %x\n",rmd->lmd_flags);
#endif DEBUG
length = 0;
goto restorebuf;
}
/* Get input data length and a pointer to the ethernet header */
length = rmd->lmd_mcnt - 4; /* don't count the 4 CRC bytes */
header = (struct ether_header *)es->es_rbuf[es->es_next_rmd];
#ifdef LANCEBUG
/*
* Check for unreported packet errors. Rev C of the LANCE chip
* has a bug which can cause "random" bytes to be prepended to
* the start of the packet. The work-around is to make sure that
* the Ethernet destination address in the packet matches our
* address.
*/
#define ether_addr_not_equal(a,b) \
( ( *(long *)(&a.ether_addr_octet[0]) != \
*(long *)(&b.ether_addr_octet[0]) ) \
|| ( *(short *)(&a.ether_addr_octet[4]) != \
*(short *)(&b.ether_addr_octet[4]) ) \
)
if( ether_addr_not_equal(header->ether_dhost, es->es_enaddr)
&& ether_addr_not_equal(header->ether_dhost, etherbroadcastaddr) ) {
printf("le: LANCE Rev C Extra Byte(s) bug; Packet punted\n");
length = 0;
/* Don't return directly; restore the buffer first */
}
#endif LANCEBUG
#ifdef DEBUG2
if( header->ether_dhost.ether_addr_octet[0] == 0xff )
printf("Broadcast packet\n");
else printf("recv np_blkno %x\n",
((struct ndpack *)(buf+14))->np_blkno);
#endif DEBUG2
/* Copy packet to user's buffer */
if ( length > 0 )
bcopy((caddr_t)header, buf, length);
restorebuf:
rmd->lmd_mcnt = 0;
rmd->lmd_flags = LMD_OWN;
/* Get ready to use the other buffer next time */
/* What about errors ? */
es->es_next_rmd = 1 - es->es_next_rmd;
return (length);
}
/*
* Close down Lance Ethernet device.
* On the Model 25, we reset the chip and take it off the wire, since
* it is sharing main memory with us (occasionally reading and writing),
* and most programs don't know how to deal with that -- they just assume
* that main memory is theirs to play with.
*/
lanceclose(sip)
struct saioreq *sip;
{
struct lance_softc *es = (struct lance_softc *) sip->si_devdata;
struct le_device *le = es->es_lance;
/* Reset the chip */
le->le_rap = LE_CSR0;
le->le_csr = LE_STOP;
}
#endif M25